#include "mainwindow.hpp"

#include <QHostAddress>
#include <QDataStream>
#include <QString>
#include <QApplication>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    _connection = new Connection(this);
    _client = new Client(this);
    _lobby = new Lobby(_client, this);

    setCentralWidget(_connection);

    _connection->show();
    _lobby->hide();
    _lobby->hideDocks();

    resize(300,150);

    connect(_connection, SIGNAL(connection(QString,quint16)), _client, SLOT(connecter(QString,quint16)));
    connect(_client, SIGNAL(connectionReussie()), this, SLOT(reactConnectionSuccess()));
    connect(_client, SIGNAL(connectionRatee()), _connection, SLOT(debloquerBouton()));
    connect(_client, SIGNAL(inscription()), this, SLOT(reactInscription()));
    connect(_client, SIGNAL(NTmotd(QString)), this, SLOT(reactMotd(QString)));
    connect(_client, SIGNAL(NTlobbySaid(QString)), _lobby, SLOT(addMessage(QString)));
    connect(_client, SIGNAL(disconnected()), this, SLOT(reactDisconnection()));

    connect(_client, SIGNAL(NTclientList(QStringList)), _lobby, SLOT(setClients(QStringList)));
    connect(_client, SIGNAL(NTclientConnected(QString)), _lobby, SLOT(addClient(QString)));
    connect(_client, SIGNAL(NTclientDisconnected(QString)), _lobby, SLOT(removeClient(QString)));

    connect(_client, SIGNAL(NTgameCreated(quint8,quint8,qreal,QString)), this, SLOT(reactGameCreated(quint8,quint8,qreal,QString)));
    connect(_client, SIGNAL(NTgameDestroyed(quint8)), this, SLOT(reactGameDestroyed(quint8)));

    connect(_client, SIGNAL(NTgameList(QList<Game*>)), this, SLOT(reactGameList(QList<Game*>)));
    connect(_client, SIGNAL(NTheSees(quint8,QString)), this, SLOT(reactHeSees(quint8,QString)));
    connect(_client, SIGNAL(NTheDoesntSeeAnymore(quint8,QString)), this, SLOT(reactHeDoesntSeeAnymore(quint8,QString)));
    connect(_client, SIGNAL(NTgameStarts(quint8,QString)), this, SLOT(reactGameStarts(quint8,QString)));
    connect(_client, SIGNAL(NTgameLeft(quint8,quint8)), this, SLOT(reactGameLeft(quint8,quint8)));
    connect(_client, SIGNAL(NTgameSaid(quint8,QString)), this, SLOT(reactGameSaid(quint8,QString)));
    connect(_client, SIGNAL(NTgameState(quint8,QStringList,QVector<QVector<quint8> >)), this, SLOT(reactGameState(quint8,QStringList,QVector<QVector<quint8> >)));
    connect(_client, SIGNAL(NTobserverList(quint8,QStringList)), this, SLOT(reactObserverList(quint8,QStringList)));
    connect(_client, SIGNAL(NTmovePlayed(quint8,quint8,quint8,quint8)), this, SLOT(reactMovePlayed(quint8,quint8,quint8,quint8)));
    connect(_client, SIGNAL(NTbadMove(quint8)), SLOT(reactBadMove(quint8)));
    connect(_client, SIGNAL(NTnewScore(quint8,quint8,qreal)), this, SLOT(reactNewScore(quint8,quint8,qreal)));
    connect(_client, SIGNAL(NTgroupKilled(quint8,quint8,quint8)), this, SLOT(reactGroupKilled(quint8,quint8,quint8)));
    connect(_client, SIGNAL(NTgroupSaved(quint8,quint8,quint8)), this, SLOT(reactGroupSaved(quint8,quint8,quint8)));
    connect(_client, SIGNAL(NTmovesFinished(quint8)), this, SLOT(reactMovesFinished(quint8)));
    connect(_client, SIGNAL(NTturnSkipped(quint8,quint8)), this, SLOT(reactTurnSkipped(quint8,quint8)));
    connect(_client, SIGNAL(NTgroupsValidated(quint8,quint8)), this, SLOT(reactGroupsValidated(quint8,quint8)));
    connect(_client, SIGNAL(NTtoPlayAgain(quint8)), this, SLOT(reactToPlayAgain(quint8)));
    connect(_client, SIGNAL(NTgameover(quint8,qreal,qreal)), this, SLOT(reactGameover(quint8,qreal,qreal)));

    setWindowIcon(QIcon("img/icon.png"));
}

void MainWindow::closeEvent(QCloseEvent * event)
{
    qApp->quit();
    event->accept();
}

void MainWindow::reactConnectionSuccess()
{
    _client->send(Mid::CONNECTION, _connection->pseudo(), _connection->hash());
}

void MainWindow::reactConnected()
{
    displayLobby(_connection->pseudo());
}

void MainWindow::displayLobby(QString pseudo)
{
    _connection->hide();
    _lobby->showDocks();
    resize(400, 300);

    setWindowTitle(pseudo);
}

void MainWindow::reactInscription()
{
    _client->send(Mid::INSCRIPTION, _connection->pseudo(), _connection->hash());
}

void MainWindow::reactMotd(const QString & message)
{
    _lobby->displayMessage("Message of the day :\n" + message + "\n");
}

void MainWindow::reactDisconnection()
{
    _lobby->addMessage("Disconnected from server!");

    _lobby->hideDocks();
    _connection->show();
    resize(300, 150);

    for (QHashIterator<quint8, Game *> it(_gameHash); it.hasNext();)
    {
        it.next();
        it.value()->destroy();
        it.value()->deleteLater();
    }

    _gameHash.clear();

    for (QHashIterator<quint8, GameWindow *> it(_gameWindowHash); it.hasNext();)
    {
        it.next();
        it.value()->deleteLater();
    }

    _gameWindowHash.clear();
}

void MainWindow::reactGameCreated(quint8 idPartie, quint8 gobanSize, qreal komi, const QString & black)
{
    Game * game = new Game(_lobby,
                           _client,
                           idPartie,
                           gobanSize,
                           komi,
                           black,
                           this);

    _gameHash[idPartie] = game;

    if (black == windowTitle()) // I created it
        reactWantToOpenAGameWindow(idPartie);
}

void MainWindow::reactToPlayAgain(quint8 idPartie)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->reactToPlayAgain();
}
void MainWindow::reactGroupsValidated(quint8 idPartie, quint8 playerID)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->reactGroupsValidated(playerID);
}
void MainWindow::reactGameover(quint8 idPartie, qreal blackScore, qreal whiteScore)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->reactGameover(blackScore, whiteScore);
}

void MainWindow::reactGameDestroyed(quint8 idPartie)
{
    if (_gameHash.contains(idPartie))
    {
        if (_gameWindowHash.contains(idPartie))
        {
            _gameWindowHash[idPartie]->gameDestroyed();
        }

        _gameHash[idPartie]->destroy();
        _gameHash[idPartie]->deleteLater();
        _gameHash.remove(idPartie);

        _lobby->removeGame(idPartie);
    }
}

void MainWindow::reactGameList(const QList<Game *> & list)
{
    for (int i = 0; i < list.size(); ++i)
        _gameHash[list[i]->id()] = list[i];
}

void MainWindow::reactGameWindowClosed(quint8 id)
{
    if (!_gameWindowHash.contains(id))
        return;
    disconnect(_gameWindowHash[id], SIGNAL(closed(quint8)), this, SLOT(reactGameWindowClosed(quint8)));

    if (_gameHash.contains(id))
        disconnect(_gameHash[id], SIGNAL(updatePlayer()), _gameWindowHash[id], SLOT(reactUpdatePlayer()));

    _gameWindowHash[id]->deleteLater();

    _gameWindowHash.remove(id);
}

void MainWindow::reactWantToOpenAGameWindow(quint8 id)
{
    if (_gameWindowHash.contains(id))
        return;

    if (!_gameHash.contains(id))
    {
        return;
    }

    GameWindow * w = new GameWindow(_client, _gameHash[id], this);
    connect(w, SIGNAL(closed(quint8)), this, SLOT(reactGameWindowClosed(quint8)));
    connect(_gameHash[id], SIGNAL(updatePlayer()), w, SLOT(reactUpdatePlayer()));

    _gameWindowHash[id] = w;

    w->setWindowTitle(windowTitle() + ", game " + QString::number(id));
    w->show();
}

void MainWindow::reactHeSees(quint8 idPartie, const QString & name)
{
    if (_gameHash.contains(idPartie))
        _gameHash[idPartie]->addObserver(name);
}

void MainWindow::reactHeDoesntSeeAnymore(quint8 idPartie, const QString & name)
{
    if (_gameHash.contains(idPartie))
        _gameHash[idPartie]->removeObserver(name);
}

void MainWindow::reactGameStarts(quint8 idPartie, const QString & name)
{
    if (_gameHash.contains(idPartie))
        _gameHash[idPartie]->addPlayer(name);
}

void MainWindow::reactGameLeft(quint8 idPartie, quint8 playerID)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->heLeft(playerID);
}

void MainWindow::reactGameSaid(quint8 idPartie, const QString & message)
{
    if (_gameWindowHash.contains(idPartie))
    {
        _gameWindowHash[idPartie]->someoneSaid(message);
    }
}

void MainWindow::reactGameState(quint8 idPartie, const QStringList & observerList, const QVector < QVector<quint8> > & map)
{
    if (_gameHash.contains(idPartie))
        _gameHash[idPartie]->setState(observerList, map);
}

void MainWindow::reactObserverList(quint8 idPartie, const QStringList & observerList)
{
    if (_gameHash.contains(idPartie))
        _gameHash[idPartie]->setObservers(observerList);
}

void MainWindow::reactMovePlayed(quint8 idPartie, quint8 playerID, quint8 x, quint8 y)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->reactMovePlayed(playerID, x, y);
}

void MainWindow::reactBadMove(quint8 idPartie)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->displayBadMove();
}

void MainWindow::reactNewScore(quint8 idPartie, quint8 playerID, qreal newScore)
{
    if (_gameWindowHash.contains(idPartie))
    {
        _gameWindowHash[idPartie]->setScore(playerID, newScore);
    }
}

void MainWindow::reactTurnSkipped(quint8 idPartie, quint8 playerID)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->skipTurn();
}

void MainWindow::reactMovesFinished(quint8 idPartie)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->setEstablishingScore(true);
}

void MainWindow::reactGroupKilled(quint8 idPartie, quint8 x, quint8 y)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->reactGroupKilled(x, y);
}

void MainWindow::reactGroupSaved(quint8 idPartie, quint8 x, quint8 y)
{
    if (_gameWindowHash.contains(idPartie))
        _gameWindowHash[idPartie]->reactGroupSaved(x, y);
}

Lobby * MainWindow::lobby() const
{
    return _lobby;
}
